/**
 * @file AsyncLogger.cpp
 * @brief 异步日志实现
 * @author Enterprise Logger Team
 * @date 2024
 */

#include "AsyncLogger.h"
#include "LogFile.h"
#include "Logger.h"
#include <cassert>
#include <chrono>
#include <iostream>
#include <cstring>

namespace logger
{

    AsyncLogger::AsyncLogger(const std::string &basename,
                             size_t rollSize,
                             int flushInterval)
        : flushInterval_(flushInterval),
          rollSize_(rollSize),
          running_(false),
          basename_(basename),
          currentBuffer_(new Buffer),
          nextBuffer_(new Buffer),
          totalWritten_(0),
          droppedLines_(0)
    {

        currentBuffer_->bzero();
        nextBuffer_->bzero();
        buffers_.reserve(16); // 预分配16个缓冲区指针空间
    }

    AsyncLogger::~AsyncLogger()
    {
        if (running_)
        {
            stop();
        }
    }

    void AsyncLogger::start()
    {
        running_ = true;
        thread_ = std::thread(&AsyncLogger::threadFunc, this);
    }

    void AsyncLogger::stop()
    {
        running_ = false;
        cond_.notify_all();
        if (thread_.joinable())
        {
            thread_.join();
        }
    }

    void AsyncLogger::append(const char *logline, int len)
    {
        std::lock_guard<std::mutex> lock(mutex_);

        // 如果当前缓冲区还有空间，直接写入
        if (currentBuffer_->avail() > len)
        {
            currentBuffer_->append(logline, len);
        }
        else
        {
            // 当前缓冲区已满，将其加入待写队列
            buffers_.push_back(std::move(currentBuffer_));

            // 使用预备缓冲区
            if (nextBuffer_)
            {
                currentBuffer_ = std::move(nextBuffer_);
            }
            else
            {
                // 极端情况：预备缓冲区也用完了，分配新的缓冲区
                currentBuffer_.reset(new Buffer);
                ++droppedLines_; // 记录这种情况（虽然不是真的丢失）
            }

            currentBuffer_->append(logline, len);

            // 通知后台线程有数据可写
            cond_.notify_one();
        }
    }

    void AsyncLogger::threadFunc()
    {
        assert(running_ == true);

        // 创建日志文件对象
        LogFile output(basename_, rollSize_, false);

        // 准备两个后备缓冲区
        BufferPtr newBuffer1(new Buffer);
        BufferPtr newBuffer2(new Buffer);
        newBuffer1->bzero();
        newBuffer2->bzero();

        // 待写入的缓冲区队列
        BufferVector buffersToWrite;
        buffersToWrite.reserve(16);

        while (running_)
        {
            assert(newBuffer1 && newBuffer1->length() == 0);
            assert(newBuffer2 && newBuffer2->length() == 0);
            assert(buffersToWrite.empty());

            {
                std::unique_lock<std::mutex> lock(mutex_);

                // 等待条件：1. 有缓冲区满了 2. 超时
                if (buffers_.empty())
                {
                    cond_.wait_for(lock, std::chrono::seconds(flushInterval_));
                }

                // 无论是超时还是被唤醒，都将当前缓冲区加入待写队列
                buffers_.push_back(std::move(currentBuffer_));

                // 使用后备缓冲区1作为新的当前缓冲区
                currentBuffer_ = std::move(newBuffer1);

                // 交换队列，减少锁持有时间
                buffersToWrite.swap(buffers_);

                // 如果预备缓冲区为空，使用后备缓冲区2
                if (!nextBuffer_)
                {
                    nextBuffer_ = std::move(newBuffer2);
                }
            } // 释放锁

            assert(!buffersToWrite.empty());

            // 异常情况：积压太多（超过25个缓冲区）
            if (buffersToWrite.size() > 25)
            {
                char buf[256];
                snprintf(buf, sizeof(buf),
                         "Dropped log messages at %s, %zd larger buffers\n",
                         logger::Timestamp::now().toString().c_str(),
                         buffersToWrite.size() - 2);
                fputs(buf, stderr);
                output.append(buf, static_cast<int>(strlen(buf)));

                // 只保留前两个缓冲区
                buffersToWrite.erase(buffersToWrite.begin() + 2, buffersToWrite.end());
                droppedLines_ += buffersToWrite.size() - 2;
            }

            // 将缓冲区内容写入文件
            for (const auto &buffer : buffersToWrite)
            {
                output.append(buffer->data(), buffer->length());
                totalWritten_ += buffer->length();
            }

            // 只保留两个缓冲区供重用
            if (buffersToWrite.size() > 2)
            {
                buffersToWrite.resize(2);
            }

            // 重置后备缓冲区
            if (!newBuffer1)
            {
                assert(!buffersToWrite.empty());
                newBuffer1 = std::move(buffersToWrite.back());
                buffersToWrite.pop_back();
                newBuffer1->reset();
            }

            if (!newBuffer2)
            {
                assert(!buffersToWrite.empty());
                newBuffer2 = std::move(buffersToWrite.back());
                buffersToWrite.pop_back();
                newBuffer2->reset();
            }

            buffersToWrite.clear();
            output.flush();
        }

        // 停止时，刷新剩余的日志
        output.flush();
    }
    void AsyncLogger::flush()
    {
        cond_.notify_one();
        // 等待一小段时间确保刷新完成
        std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }

} // namespace logger
